/**
 * @author Xin Xiao
 * @version 1.0.0
 * @date 20210309
 * @copyright MIN-Group:国家重大科技基础设施-未来网络北大实验室：深圳市信息论与未来网络重点实验室
 */

 var SelfEncodingBase = require('../encoding/SelfEncodingBase').SelfEncodingBase
 var Encoder = require('../encoding/Encoder').Encoder
 var Block = require('../encoding/Block').Block
 var TLV = require('../encoding/TLV')
 var ComponentType = require("../encoding/TLV").ComponentType
 var TlvComponentBase = require('./TlvComponentBase').TlvComponentBase
 var aggregation = require('../common/aggregation')//实现了多继承
var SignatureType = require('./SignatureType').SignatureType
var KeyLocator = require('./KeyLocator').KeyLocator

/**
 * @description 表示签名的元数据，包含；签名类型、用于签名的证书或公钥的位置
 * 1.格式如下：
 * SignatureInfo = 201 TLV-LENGTH
 * <SignatureType>
 * [KeyLocator]
 * 2.详情参加：http://gitea.qjm253.cn/PKUSZ-future-network-lab/minlib/src/branch/master/docs/PacketFormat.md#4-signature
 */

 class SignatureInfo extends aggregation(SelfEncodingBase){
   constructor(){
     super()
     this.signatureType = new SignatureType()
     this.keyLocator = new KeyLocator()
   }

   /**
    * @description 根据签名类型值初始化当前 SignatureInfo
    * @param {SignatureTypeValue} signatureTypeValue
    */
   buildSignatureInfoBySignatureTypeValue(signatureTypeValue){
     try {
      this.signatureType.buildSignatureTypeByValue(signatureTypeValue)
     } catch (error) {
       throw error
     }
   }

   /**
    * @description 根据签名值和 KeyLocator 初始化当前 SignatureInfo
    * @param {number} value
    * @param {KeyLocator} locator
    * @todo kerylocate
    */
   buildSignatureInfoBySignatureTypeValueAndKeyLocator(value,locator){
     try {
       this.signatureType.buildSignatureTypeByValue(value)
       this.keyLocator.buildKeyLocatorByIdentifier(locator.getIdentifier())
     } catch (error) {
       throw error
     }
   }

   /**
    * @description 根据 TLV Block 初始化当前SignatureInfo
    * @param {Block} block
    */
   buildSignatureInfoByBlock(block){
    try {
      this.wireDecode(block)
    } catch (error) {
      throw error
    }
   }

   /**
    * @description 获得签名类型
    * @return {SignatureType}
    */
   getSignatureType(){
     return this.signatureType
   }

   /**
    * @description 获得 KeyLocator
    * @return {KeyLoctor}
    */
   getKeyLocator(){
     return this.keyLocator
   }

   /**
   * @description 将 SignatureInfo 线速编码为 TLV
   * @param {Encoder} Encoder
   * @return {number} totalLength
   */
  wireEncode(encoder){
		let totalLength = 0
    if(this.keyLocator.isValid()){
      // KeyLocator 是可选的，如果当前 SignatureInfo 对象有一个有效的 KeyLocator，则对其进行编码
      try {
        let tmpLen = this.keyLocator.wireEncode(encoder)
        totalLength +=tmpLen
      } catch (error) {
        throw error
      }
    }
		try {
			let tmpLen = this.signatureType.wireEncode(encoder)
			totalLength += tmpLen

			//编码 TLV-LENGTH
			tmpLen = encoder.prependVarNumber(BigInt(totalLength))
			totalLength += tmpLen

			//编码 TLV-TYPE
			tmpLen = encoder.prependVarNumber(ComponentType.TlvSignatureInfo)
			totalLength += tmpLen

			return totalLength
		} catch (error) {
			throw error
		}
	}

  /**
	 * @description 从 TLV Block 中解码出一个SignatureInfo
	 * @param {Block} block
	 */
	wireDecode(block){
    let result
		try {
			//检查Type是否正确
			TLV.expectType(block.getType(),ComponentType.TlvSignatureInfo)
      // 解析子组件
      block.parseSubElements()
    }catch(error){
      throw error
    }
      let findSignatureType = false
      for(var element of block.getSubElements()){
        switch (element.getType()){
          case ComponentType.TlvSignatureType:
            try {
              this.signatureType.wireDecode(element)
            } catch (error) {
              throw error
            }
            findSignatureType = true
            break;
          case ComponentType.TlvKeyLocator:
            try {
              this.keyLocator.wireDecode(element)
              break;
            } catch (error) {
              throw error
            }
          default:
            throw new SignatureInfoError("current element type:"+element.getType())
        }
      }

      // 缺失必要的 SignatureType 子TLV
      if(! findSignatureType){
        let e = new SignatureInfoError()
        e.msg = "Parse SignatureInfo error, require SignatureType sub-element"
        throw e
      }
	}
 }

 /**
  * @description 根据签名值类型创建一个 SignatureInfo
  * @param {number} value
  * @return {signatureInfo}
  */
 function createSignatureInfoBySignatureTypeValue(value){
   var signatureInfo = new SignatureInfo()
   try {
     signatureInfo.buildSignatureInfoBySignatureTypeValue(value)
     return signatureInfo
   } catch (error) {
     throw error
   }
 }

 /**
  * @description 根据签名值类型和 KeyLocator 创建一个 SignatureInfo
  * @param {number} value
  * @param {KeyLocator} locator
  * @return {SignatureInfo}
  */
 function createSignatureInfoBySignatureTypeValueAndKeyLocator(value,locator){
  var signatureInfo = new SignatureInfo()
  try {
    signatureInfo.buildSignatureInfoBySignatureTypeValueAndKeyLocator(value,locator)
  } catch (error) {
    throw error    
  }
  return signatureInfo
 }

 /**
  * @description 根据 TLV Block 创建一个 SignatureInfo
  * @param {Block} Block
  * @return {SignatureInfo}
  */
 function createSignatureInfoByBlock(block){
  var signatureInfo = new SignatureInfo()
  try {
    signatureInfo.buildSignatureInfoByBlock(block)
    return signatureInfo
  } catch (error) {
    throw error    
  }
 }

 // 错误处理
 class SignatureInfoError{
   constructor(string){
     this.msg = string||""
   }

   static error(){
     console.log("SignatureInfoError: "+this.msg)
   }
 }

 module.exports = {
  SignatureInfo: SignatureInfo,
  SignatureInfoError: SignatureInfoError,
  createSignatureInfoByBlock: createSignatureInfoByBlock,
  createSignatureInfoBySignatureTypeValue: createSignatureInfoBySignatureTypeValue,
  createSignatureInfoBySignatureTypeValueAndKeyLocator: createSignatureInfoBySignatureTypeValueAndKeyLocator
 }